package com.company.eos.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.company.eos.common.BusinessException;
import com.company.eos.common.ErrorEnum;
import com.company.eos.common.GlobalException;
import com.company.eos.controller.form.user.LoginForm;
import com.company.eos.controller.form.user.UpdatePasswordDTO;
import com.company.eos.controller.form.user.UpdateProfileDTO;
import com.company.eos.mapper.LoginAuthorMapper;
import com.company.eos.mapper.UserMapper;
import com.company.eos.domain.LoginAuthor;
import com.company.eos.domain.User;
import com.company.eos.service.LoginAuthorService;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author Xmirror
 * @description 针对表【sys_login_author(登录授权)】的数据库操作Service实现
 * @createDate 2022-03-18 15:39:37
 */
@Service
public class LoginAuthorServiceImpl extends ServiceImpl<LoginAuthorMapper, LoginAuthor>
        implements LoginAuthorService {

    @Resource
    private LoginAuthorMapper loginAuthorMapper;
    @Resource
    private UserMapper userMapper;

    /**
     * 用户登录
     *
     * @param dto 包含登录账户和密码
     * @return 登录的用户生成的 TOKEN
     */
    @Override
    public User login(LoginForm dto) {
        String loginAccount = dto.getUsername();
        String password = dto.getPassword();
        if (StringUtils.isBlank(loginAccount) || StringUtils.isBlank(password)) {
            throw new BusinessException(ErrorEnum.LOGIN_INPUT_EMPTY_ERROR);
        }
        // 登录授权表
        LoginAuthor loginAuthor = this.getByAccount(loginAccount);
        if (loginAuthor == null) {
            throw new BusinessException(ErrorEnum.USER_NOT_EXIST);
        }
        String temp = new Sha256Hash(password, loginAuthor.getSalt()).toHex();
        if (!temp.equals(loginAuthor.getPassword())) {
            throw new BusinessException(ErrorEnum.PASSWORD_INCORRECT_ERROR);
        }
        // 查询出登录用户
        User user = this.getUserByAccount(loginAccount);
        if (user == null) {
            throw new BusinessException(ErrorEnum.USER_NOT_EXIST);
        }
        return user;
    }

    /**
     * 通过账号获取登录权限表
     *
     * @param loginAccount 登录账号
     * @return 登录权限
     */
    @Override
    public LoginAuthor getByAccount(String loginAccount) {
        return loginAuthorMapper.selectOne(new LambdaQueryWrapper<LoginAuthor>()
                .eq(LoginAuthor::getLoginAccount, loginAccount));
    }

    /**
     * 根据登录账号获取用户
     *
     * @param loginAccount 登录账号
     * @return User
     */
    @Override
    public User getUserByAccount(String loginAccount) {
        LoginAuthor loginAuthor = loginAuthorMapper.selectOne(new LambdaQueryWrapper<LoginAuthor>()
                .eq(LoginAuthor::getLoginAccount, loginAccount));
        if (loginAuthor != null && loginAuthor.getUserId() != null) {
            Integer userId = loginAuthor.getUserId();
            return userMapper.selectById(userId);
        } else {
            return null;
        }
    }

    /**
     * 用户更新密码
     *
     * @param dto 用户更新密码DTO对象
     * @return 更新的行数，默认为 1
     */
    @Override
    public Integer updatePassword(UpdatePasswordDTO dto) {
        // 合法性检验
        if (dto == null || dto.getPassword() == null ||
                dto.getUserId() == null) {
            throw new GlobalException(ErrorEnum.UPDATE_PASSWORD_INPUT_ERROR);
        }

        String password = dto.getPassword();
        Integer userId = dto.getUserId();
        if (dto.getUserId() == null) {
            throw new GlobalException(ErrorEnum.USER_ID_NULL_ERROR);
        }
        // 重置密码 salt 也一样更换
        String salt = RandomStringUtils.randomAlphanumeric(20);
        String newPassword = new Sha256Hash(password, salt).toHex();
        // 更新用户密码
        return loginAuthorMapper.updatePasswordByUserId(userId, newPassword, salt);
    }

    /**
     * 更新用户的个人信息（会影响到登录账号，所以涉及到登录表的修改）
     *
     * @param dto dto对象，包括用户ID、手机、邮箱
     * @return 更新的数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateProfile(UpdateProfileDTO dto) {
        if (dto.getUserId() == null) {
            throw new BusinessException(ErrorEnum.USER_ID_NULL_ERROR);
        }
        Integer userId = dto.getUserId();
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new GlobalException(ErrorEnum.USER_NOT_EXIST);
        }
        // 更新用户登录表
        List<LoginAuthor> loginAuthors = loginAuthorMapper.selectList(Wrappers.lambdaQuery(LoginAuthor.class)
                .eq(LoginAuthor::getUserId, userId));
        int update = 0;
        if (loginAuthors != null && loginAuthors.size() != 0) {
            // 原本登录账号齐全，应该修改原有的登录账号
            if (loginAuthors.size() == 4) {
                for (LoginAuthor loginAuthor : loginAuthors) {
                    String loginAccount = loginAuthor.getLoginAccount();
                    if (loginAccount.equals(user.getEmail())) {
                        update += loginAuthorMapper.updateLoginAccount(loginAccount, dto.getEmail());
                    }
                    if (loginAccount.equals(user.getTel())) {
                        update += loginAuthorMapper.updateLoginAccount(loginAccount, dto.getPhone());
                    }
                }
            } else {
                // 原本登录账号缺少，可能需要添加对应的账号
                int emailFlag = 0, phoneFlag = 0;
                for (LoginAuthor loginAuthor : loginAuthors) {
                    String loginAccount = loginAuthor.getLoginAccount();
                    if (loginAccount.equals(user.getEmail())) {
                        emailFlag = 1;
                        update += loginAuthorMapper.updateLoginAccount(loginAccount, dto.getEmail());
                    }
                    if (loginAccount.equals(user.getTel())) {
                        phoneFlag = 1;
                        update += loginAuthorMapper.updateLoginAccount(loginAccount, dto.getPhone());
                    }
                }
                if (emailFlag == 0) {
                    this.insertLoginAccount(dto.getEmail(), userId);
                }
                if (phoneFlag == 0) {
                    this.insertLoginAccount(dto.getPhone(), userId);
                }
            }
        } else {
            // 如果登陆表为空，新增
            if (dto.getPhone() != null) {
                update += this.insertLoginAccount(dto.getPhone(), userId);
            }
            if (dto.getEmail() != null) {
                update += this.insertLoginAccount(dto.getEmail(), userId);
            }
        }
        // 更新用户表格
        user.setEmail(dto.getEmail());
        user.setTel(dto.getPhone());
        int count = userMapper.updateById(user);
        return (count == 1 || update >= 1) ? update : null;
    }

    /**
     * 新增登录账号
     *
     * @param account 登录账号
     * @param userId  用户ID
     * @return 新增的数量
     */
    @Override
    public Integer insertLoginAccount(String account, Integer userId) {
        List<LoginAuthor> loginAuthors = loginAuthorMapper.selectList(Wrappers.lambdaQuery(LoginAuthor.class)
                .eq(LoginAuthor::getUserId, userId));
        if (loginAuthors == null) {
            throw new GlobalException(ErrorEnum.LOGIN_ACCOUNT_NOT_EXIST);
        }
        String password = loginAuthors.get(0).getPassword();
        String salt = loginAuthors.get(0).getSalt();
        LoginAuthor loginAuthor = new LoginAuthor();
        loginAuthor.setLoginAccount(account);
        loginAuthor.setUserId(userId);
        loginAuthor.setPassword(password);
        loginAuthor.setSalt(salt);
        return loginAuthorMapper.insert(loginAuthor);
    }

    /**
     * 测试时生成登录账号所需
     * 在用户信息完备的情况下，生成的数量预计为用户数*4
     *
     * @return 生成的数量
     */
    @Override
    public Integer generatorLoginAccount() {
        List<User> users = userMapper.selectList(null);
        int count = 0;
        for (User user : users) {
            String phone = user.getTel();
            String email = user.getEmail();
            Integer userId = user.getId();
            String username = user.getUsername();
            if (phone != null) {
                count += this.insertLoginAuthor(phone, userId);
            }
            if (email != null) {
                count += this.insertLoginAuthor(email, userId);
            }
            if (username != null) {
                count += this.insertLoginAuthor(username, userId);
            }
        }
        return count;
    }

    /**
     * 根据用户插入用户的登录账号
     *
     * @param user 用户
     * @return 新增的数量
     */
    @Override
    public Integer insertLoginAccountByUser(User user) {
        int count = 0;
        String phone = user.getTel();
        String email = user.getEmail();
        Integer userId = user.getId();
        String username = user.getUsername();
        if (phone != null) {
            count += this.insertLoginAuthor(phone, userId);
        }
        if (email != null) {
            count += this.insertLoginAuthor(email, userId);
        }
        if (username != null) {
            count += this.insertLoginAuthor(username, userId);
        }
        return count;
    }

    /**
     * 根据用户的ID删除用户登录账号
     *
     * @param userId 用户ID
     * @return 删除的数量
     */
    @Override
    public Integer deleteLoginAccountByUserId(int userId) {
        return loginAuthorMapper.delete(Wrappers.lambdaQuery(LoginAuthor.class)
                .eq(LoginAuthor::getUserId, userId));
    }

    /**
     * 插入默认的登录账号
     *
     * @param loginAccount 登录账号
     * @param userId       用户ID
     * @return 插入的行数
     */
    private Integer insertLoginAuthor(String loginAccount, Integer userId) {
        String tempPassword = new Sha256Hash("123456",
                "MTNCzbi3fK1a4251zNZQ").toHex();
        String salt = "MTNCzbi3fK1a4251zNZQ";
        LoginAuthor loginAuthor = new LoginAuthor(tempPassword, salt, loginAccount, userId);
        return loginAuthorMapper.insert(loginAuthor);
    }

}




